package nm.aleksey.client.widgets;

import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.CellPreviewEvent;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.DefaultSelectionEventManager.SelectAction;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.web.bindery.requestfactory.shared.EntityProxyChange;
import com.google.web.bindery.requestfactory.shared.EntityProxyId;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.WriteOperation;
import nm.aleksey.client.ClientFactory;
import nm.aleksey.client.events.EditAuthorEvent;
import nm.aleksey.shared.AuthorContext;
import nm.aleksey.shared.AuthorProxy;
import nm.aleksey.shared.TableRequestFactory;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;

//import nm.aleksey.client.events.EditBookEvent;
//import nm.aleksey.shared.BookContext;
//import nm.aleksey.shared.BookProxy;

public class Table extends Composite {

  private class CheckboxEventTranslatorExtension extends
      DefaultSelectionEventManager.BlacklistEventTranslator<AuthorProxy> {

    @Override
    public SelectAction translateSelectionEvent(
        CellPreviewEvent<AuthorProxy> event) {

      AuthorProxy author = event.getValue();
      Table.this.author = author;
      String nativeEventType = event.getNativeEvent().getType();

      switch (event.getColumn()) {
      case 0:
        if (authorSetToDelete.contains(author)) {
          authorSetToDelete.remove(author);
        } else {
          authorSetToDelete.add(author);
        }
        break;
      case 3:
        if ("mouseover".equals(nativeEventType)
            || "mouseout".equals(nativeEventType)
            || "mousedown".equals(nativeEventType)
            || "focus".equals(nativeEventType)
            || "keydown".equals(nativeEventType)
            || "keyup".equals(nativeEventType)
            || "blur".equals(nativeEventType)) {
          break;
        }
//        AuthorContext authorContext = Table.this.getRequestFactory()
//            .authorRequest();
//        authorContext.getBookList(author).fire(new Receiver<List<BookProxy>>() {
//
//          @Override
//          public void onSuccess(List<BookProxy> response) {
//            if (response == null) {
//              return;
//            }
//            bookListBox.clear();
//            String bookHtml = "";
//            for (BookProxy book : response) {
//              bookHtml = book.getName() + " | " + book.getIsdn();
//              bookListBox.addItem(bookHtml, book.getId());
//            }
//          }
//        });
        break;
      }

      SelectAction action = super.translateSelectionEvent(event);
      return action;
    }
  }

//  private class RemoveBookClickHandler implements ClickHandler {
//
//    @Override
//    public void onClick(ClickEvent event) {
//      if (event.isAltKeyDown()) {
//        int index = bookListBox.getSelectedIndex();
//        if (Window.confirm("Вы действительно хотите удалить книгу "
//            + bookListBox.getItemText(index) + "?")) {
//          String id = bookListBox.getValue(index);
//          bookListBox.removeItem(index);
//          getRequestFactory().bookRequest().find(id)
//              .fire(new Receiver<BookProxy>() {
//
//                @Override
//                public void onSuccess(BookProxy response) {
//                  getRequestFactory().bookRequest().delete(response).fire();
//                }
//
//              });
//        }
//      }
//    }
//  }

  interface TableUiBinder extends UiBinder<Widget, Table> {
  }

  private static TableUiBinder uiBinder = GWT.create(TableUiBinder.class);

  @UiField
  Button addAuthorButton;
//  @UiField
//  Button addBookButton;
  private AuthorProxy author;
  private final HashSet<AuthorProxy> authorSetToDelete = new HashSet<AuthorProxy>();
  @UiField
  CellTable<AuthorProxy> authorTable;
//  @UiField
//  ListBox bookListBox;
  private final ClientFactory clientFactory;
  @UiField
  Button deleteAuthorButton;
  private int lastFetch;
  private final SingleSelectionModel<AuthorProxy> selectionModel = new SingleSelectionModel<AuthorProxy>();

  public Table(ClientFactory clientFactory) {
    initWidget(uiBinder.createAndBindUi(this));
    this.clientFactory = clientFactory;

    Column<AuthorProxy, Boolean> checkboxColumn = new Column<AuthorProxy, Boolean>(
        new CheckboxCell(true, false)) {
      @Override
      public Boolean getValue(AuthorProxy object) {
        if (object == null || object.stableId() == null) {
          return null;
        }
        return selectionModel.isSelected(object);
      }
    };

    TextColumn<AuthorProxy> nameColumn = new TextColumn<AuthorProxy>() {
      @Override
      public String getValue(AuthorProxy object) {
        return object.getName();
      }
    };

    TextColumn<AuthorProxy> emailColumn = new TextColumn<AuthorProxy>() {
      @Override
      public String getValue(AuthorProxy object) {
        return object.getEmail();
      }
    };

    TextColumn<AuthorProxy> addressColumn = new TextColumn<AuthorProxy>() {
      @Override
      public String getValue(AuthorProxy object) {
        return object.getAddress();
      }
    };

//    TextColumn<AuthorProxy> viewColumn = new TextColumn<AuthorProxy>() {
//      @Override
//      public String getValue(AuthorProxy object) {
//        return "Выбрать";
//      }
//    };
//    viewColumn.setCellStyleNames("cell-link");

    CheckboxEventTranslatorExtension translator = new CheckboxEventTranslatorExtension();
    translator.setColumnBlacklisted(0, true);
    translator.setColumnBlacklisted(3, true);
    DefaultSelectionEventManager<AuthorProxy> selectionManager = DefaultSelectionEventManager
        .createCustomManager(translator);

    authorTable.addColumn(checkboxColumn);
    authorTable.addColumn(nameColumn, "Название");
    authorTable.addColumn(emailColumn, "Электронная почта");
    authorTable.addColumn(addressColumn, "Юридический адрес");
//    authorTable.addColumn(viewColumn);

    authorTable.setSelectionModel(selectionModel, selectionManager);
    selectionModel
        .addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
          @Override
          public void onSelectionChange(SelectionChangeEvent event) {
            Table.this.refreshSelection();
          }
        });

//    bookListBox.addClickHandler(new RemoveBookClickHandler());

    EntityProxyChange.registerForProxyType(this.clientFactory.getEventBus(),
        AuthorProxy.class, new EntityProxyChange.Handler<AuthorProxy>() {
          @Override
          public void onProxyChange(EntityProxyChange<AuthorProxy> event) {
            Table.this.onAuthorChanged(event);
          }
        });

    fetch(0);
  }

  private void fetch(final int start) {
    lastFetch = start;
    TableRequestFactory requestFactory = getClientFactory().getRequestFactory();
    AuthorContext authorContext = requestFactory.authorRequest();
    authorContext.findAll().fire(new Receiver<List<AuthorProxy>>() {

      @Override
      public void onSuccess(List<AuthorProxy> response) {
        if (response == null) {
          return;
        }
        if (lastFetch != start) {
          return;
        }
        authorTable.setRowCount(response.size(), false);
        authorTable.setRowData(start, response);
      }
    });
  }

  public ClientFactory getClientFactory() {
    return clientFactory;
  }

  private TableRequestFactory getRequestFactory() {
    return clientFactory.getRequestFactory();
  }

  private int offsetOf(EntityProxyId<AuthorProxy> personId) {
    List<AuthorProxy> displayedItems = authorTable.getVisibleItems();
    for (int offset = 0, j = displayedItems.size(); offset < j; offset++) {
      if (personId.equals(displayedItems.get(offset).stableId())) {
        return offset;
      }
    }
    return -1;
  }

  @UiHandler("addAuthorButton")
  void onAddAuthorButtonClick(ClickEvent event) {
    AuthorContext context = getRequestFactory().authorRequest();
    AuthorProxy author = context.create(AuthorProxy.class);
    context.save(author);
    getClientFactory().getEventBus().fireEvent(
        new EditAuthorEvent(author, context));
  }

//  @UiHandler("addBookButton")
//  void onAddBookButtonClick(ClickEvent event) {
//    if (author == null) {
//      Window.alert("Пожалуйста, выберите автора.");
//      return;
//    }
//
//    BookContext context = getRequestFactory().bookRequest();
//    BookProxy book = context.create(BookProxy.class);
//    getClientFactory().getEventBus().fireEvent(
//        new EditBookEvent(bookListBox, author, book, context));
//  }

  protected void onAuthorChanged(EntityProxyChange<AuthorProxy> event) {
    if (WriteOperation.PERSIST.equals(event.getWriteOperation())) {
      fetch(0);
    }
    if (WriteOperation.UPDATE.equals(event.getWriteOperation())) {
      EntityProxyId<AuthorProxy> authorId = event.getProxyId();

      // Is the changing record onscreen?
      int displayOffset = offsetOf(authorId);
      if (displayOffset != -1) {
        // Record is onscreen and may differ from our data
        getRequestFactory().find(authorId).fire(new Receiver<AuthorProxy>() {
          @Override
          public void onSuccess(AuthorProxy author) {
            // Re-check offset in case of changes while waiting for data
            int offset = offsetOf(author.stableId());
            if (offset != -1) {
              authorTable.setRowData(offset, Collections.singletonList(author));
            }
          }
        });
      }
    }
  }

  @UiHandler("deleteAuthorButton")
  void onRemoveAuthorButtonClick(ClickEvent event) {
    if (authorSetToDelete.isEmpty()) {
      return;
    }
    AuthorContext authorContext = getRequestFactory().authorRequest();
    for (AuthorProxy author : authorSetToDelete) {
      authorContext.delete(author);
    }

    authorContext.fire(new Receiver<Void>() {

      @Override
      public void onSuccess(Void response) {
        authorSetToDelete.clear();
        GWT.log("List of authors was cleared.");
        fetch(0);
      }

    });
  }

  protected void refreshSelection() {
    AuthorProxy author = selectionModel.getSelectedObject();
    if (author == null) {
      return;
    }
    getClientFactory().getEventBus().fireEvent(new EditAuthorEvent(author));
    selectionModel.setSelected(author, false);
  }
}
